package core

import (
	"github.com/gookit/color"
	"gorm.io/gorm"
	"io/ioutil"
	"os"
	"path"
	"seven-admin/app/collection/common"
	"seven-admin/app/collection/system"
	"strconv"
	"strings"
)

// migrate 函数中通过引入变量存储 dst() 的结果，避免重复调用 dst()
func migrate(db *gorm.DB) error {
	models := dst()
	err := db.AutoMigrate(models...)
	if err != nil {
		return err
	}
	return fill(db, models)
}

func dst() []interface{} {
	return []interface{}{
		// common
		&common.Album{},
		&common.AlbumCate{},
		&common.Dictionaries{},
		// system
		&system.Config{},
		&system.AuthAdmin{},
		&system.AuthMenu{},
		&system.AuthPerm{},
		&system.AuthRole{},
		&system.AuthDept{},
		&system.AuthPost{},
		&system.LoginLog{},
		&system.OperateLog{},
		&system.AuthTenant{},
		&system.AuthTenantPerm{},
	}
}

// fill 函数中增加 models 参数，避免重复调用 dst()
func fill(db *gorm.DB, models []interface{}) error {
	var count int64
	for _, model := range models {
		if err := db.Model(model).Count(&count).Error; err != nil {
			return err
		}
		if count > 0 {
			continue
		}
		tableName := getTableName(db, model)
		//color.Blueln("checking table: ", tableName)
		if checkSQLFile(tableName) {
			sqlContent, err := readSQLFile(tableName)
			if err != nil {
				return err
			}
			if err = db.Exec(sqlContent).Error; err != nil {
				return err
			}
			// 更新序列当前值
			var id uint
			if err = db.Model(model).Order("id desc").Select("id").First(&id).Error; err != nil {
				color.Redln("update sequence error: ", err)
				continue
			}
			if id > 0 {
				if err = db.Exec("ALTER SEQUENCE " + tableName + "_id_seq RESTART WITH " + strconv.Itoa(int(id)+1)).Error; err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func readSQLFile(tableName string) (string, error) {
	sqlFilePath, err := getSQLFilePath(tableName)
	if err != nil {
		return "", err
	}
	data, err := ioutil.ReadFile(sqlFilePath)
	if err != nil {
		return "", err
	}
	replacedContent := strings.ReplaceAll(string(data), "{table_name}", tableName)
	return replacedContent, nil
}

func getTableName(db *gorm.DB, model interface{}) string {
	stmt := &gorm.Statement{DB: db}
	_ = stmt.Parse(model)
	return stmt.Schema.Table
}

// 判断sql文件是否存在，如果文件不存在则返回错误，避免不必要的处理
func checkSQLFile(tableName string) bool {
	filePath, err := getSQLFilePath(tableName)
	if err != nil {
		color.Redln("get sql file path error: ", err)
		return false
	}
	_, err = os.Stat(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
		return false
	}
	return true
}

// 提取获取 SQL 文件路径的逻辑到单独的函数中，避免代码重复
func getSQLFilePath(tableName string) (string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	return path.Join(wd, "sql", tableName+".sql"), nil
}
